#pragma once

#ifndef ASIO_STANDALONE
#define ASIO_STANDALONE
#define ASIO_NO_DEPRECATED
#endif
#include "asio/buffer.hpp"
#include "buffer.hpp"


namespace asio
{

class RecvBuffer
{
private:
	std::shared_ptr<KRPC::Buffer> mybuf;
	asio::mutable_buffer rcvbuf;

	void prepare(std::size_t allocsize)
	{
		mybuf = std::make_shared<KRPC::Buffer>(allocsize, allocsize);
		if (mybuf && *mybuf)
			rcvbuf = asio::mutable_buffer(mybuf->data(), mybuf->len());
		else
			mybuf = nullptr;
	}

public:
	RecvBuffer() = default;
	RecvBuffer(std::size_t allocsize) { prepare(allocsize); }
	RecvBuffer(std::size_t allocsize, const void *head, std::size_t headsize)
	{
		if (allocsize < headsize)
			return;
		prepare(allocsize);
		if (mybuf && *mybuf) {
			memcpy(mybuf->data(), head, headsize);
			rcvbuf += headsize;
		}
	}

	std::shared_ptr<KRPC::Buffer> buffer() const
	{
		return mybuf;
	}

	// Implement the MutableBufferSequence requirements.
	typedef asio::mutable_buffer value_type;
	typedef const asio::mutable_buffer* const_iterator;
	typedef asio::mutable_buffer* iterator;
	const_iterator begin() const { return &rcvbuf; }
	const_iterator end() const { return &rcvbuf + 1; }
	iterator begin() { return &rcvbuf; }
	iterator end() { return &rcvbuf + 1; }
	
	const void *data() const { return mybuf->data(); }
	void *data() { return mybuf->data(); }
	std::size_t size() const { return mybuf->len(); }
	explicit operator bool() const { return (mybuf && *mybuf); }

};

class SendBuffer
{
private:
	std::shared_ptr<KRPC::Buffer> mybuf;
	asio::const_buffer sndbuf;

public:
	SendBuffer(std::shared_ptr<KRPC::Buffer> buf) : mybuf(std::move(buf)), sndbuf(mybuf->data(), mybuf->len()) {}

	// Implement the MutableBufferSequence requirements.
	typedef asio::const_buffer value_type;
	typedef const asio::const_buffer* const_iterator;
	//typedef asio::const_buffer* iterator;
	const_iterator begin() const { return &sndbuf; }
	const_iterator end() const { return &sndbuf + 1; }
	//iterator begin() const { return &sndbuf; }
	//iterator end() const { return &sndbuf + 1; }
	explicit operator bool() const { return (mybuf && *mybuf); }

};

}

